/*
 * Copyright (C)  Tony Green, LitePal Framework Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.litepal.tablemanager;


import ohos.app.Environment;
import ohos.data.DatabaseHelper;
import ohos.data.rdb.RdbOpenCallback;
import ohos.data.rdb.RdbStore;
import ohos.data.rdb.StoreConfig;
import ohos.data.usage.DataUsage;
import ohos.data.usage.MountState;
import ohos.data.usage.Volume;
import org.litepal.LitePalApplication;
import org.litepal.Operator;
import org.litepal.parser.LitePalAttr;
import org.litepal.tablemanager.callback.DatabaseListener;
import org.litepal.util.SharedUtil;
import org.litepal.util.TextUtils;

import java.io.File;
import java.util.List;
import java.util.Optional;

/**
 * The connector to connect database provided by LitePal. Users can use this
 * class to get the instance of RdbStore. But users still need to write
 * their own CRUD logic by the returned RdbStore. It will be improved in
 * the future.
 * 
 * @author Tony Green
 * @since 1.0
 */
public class Connector {

    /**
     * The quote of LitePalHelper.
     */
//    private static LitePalOpenHelper mLitePalHelper;

    private static RdbStore store;
    /**
     * Get a writable RdbStore.
     * 
     * There're a lot of ways to operate database in harmony. But LitePal
     * doesn't support using ContentProvider currently. The best way to use
     * LitePal well is get the RdbStore instance and use the methods like
     * RdbStore#save, RdbStore#update, RdbStore#delete,
     * RdbStore#query in the RdbStore class to do the database
     * operation. It will be improved in the future.
     * 
     * @return A writable RdbStore instance
     */
    public synchronized static RdbStore getWritableDatabase() {
//        LitePalOpenHelper litePalHelper = buildConnection();
        return buildConnection();
    }

    /**
     * Call getDatabase directly will invoke the getWritableDatabase method by
     * default.
     * 
     * This is method is alias of getWritableDatabase.
     * 
     * @return A writable RdbStore instance
     */
    public static RdbStore getDatabase() {
        return getWritableDatabase();
    }

    /**
     * Build a connection to the database. This progress will analysis the
     * litepal.xml file, and will check if the fields in LitePalAttr are valid,
     * and it will open a SQLiteOpenHelper to decide to create tables or update
     * tables or doing nothing depends on the version attributes.
     * 
     * After all the stuffs above are finished. This method will return a
     * LitePalHelper object.Notes this method could throw a lot of exceptions.
     * 
     * @return LitePalHelper object.
     */
    private static RdbStore buildConnection() {
        LitePalAttr litePalAttr = LitePalAttr.getInstance();
        litePalAttr.checkSelfValid();
        if (store == null) {
            String dbName = litePalAttr.getDbName();
//            if ("external".equalsIgnoreCase(litePalAttr.getStorage())) {
//                dbName = LitePalApplication.getSContext().getDatabaseDir() + "/" + dbName;
//            } else if (!"internal".equalsIgnoreCase(litePalAttr.getStorage()) && !TextUtils.isEmpty(litePalAttr.getStorage())) {
//                // internal or empty means internal storage, neither or them means sdcard storage
//
//                String dbPath = LitePalApplication.getSContext().getExternalCacheDir() + "/" + litePalAttr.getStorage();
//                dbPath = dbPath.replace("//", "/");
//                File path = new File(dbPath);
//                if (!path.exists()) {
//                    path.mkdirs();
//                }
//                dbName = dbPath + "/" + dbName;
//            }
//            mLitePalHelper = new LitePalOpenHelper(dbName, litePalAttr.getVersion());

            StoreConfig config = StoreConfig.newDefaultConfig(dbName);
            DatabaseHelper helper = new DatabaseHelper(LitePalApplication.getSContext());
            store = helper.getRdbStore(config, litePalAttr.getVersion(), callback, null);
        }
        return store;
    }

    /**
     * Never call this method. This is only used by internal.
     */
    public static void clearLitePalOpenHelperInstance() {
        if (store != null) {
            store.close();
            store = null;
        }
    }
    private static final RdbOpenCallback callback = new RdbOpenCallback() {
        @Override
        public void onCreate(RdbStore store) {
            Generator.create(store);
            final DatabaseListener listener = Operator.getDBListener();
            if (listener != null) {
                LitePalApplication.sHandler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        listener.onCreate();
                    }
                });
            }
        }
        @Override
        public void onUpgrade(RdbStore store, int oldVersion, int newVersion) {
            Generator.upgrade(store);
            SharedUtil.updateVersion(LitePalAttr.getInstance().getExtraKeyName(), newVersion);
            final DatabaseListener listener = Operator.getDBListener();
            if (listener != null) {
                LitePalApplication.sHandler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        listener.onUpgrade(oldVersion, newVersion);
                    }
                });
            }
        }};
}

